package gang.org.springframework.framework.asm;

import gang.org.springframework.framework.metadata.GangMergedAnnotation;
import gang.org.springframework.framework.util.GangClassUtils;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
 * GangMergedAnnotationReadingVisitor 继承自 AnnotationVisitor，
 * A AnnotationVisitor to visit a Java annotation. The methods of this class must be
 * called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
 * <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
 * 执行的次序为
 * 1）visit
 * 2）visitEnum
 * 3）visitAnnotation
 * 4）visitArray
 * 5）visitEnd
 * @author gang.chen
 */
public class GangMergedAnnotationReadingVisitor<A extends Annotation> extends AnnotationVisitor {

    private final ClassLoader classLoader;

    private final Object source;

    private final Class<A> annotationTypes;

    private final Consumer<GangMergedAnnotation<A>> consumer;

    private final Map<String, Object> attributes = new LinkedHashMap<>(4);

    /**
     *TODO
     *
     * */
    public GangMergedAnnotationReadingVisitor(ClassLoader classLoader,
                                              Object source,
                                              Class<A> annotationType,
                                              Consumer<GangMergedAnnotation<A>> consumer){
        super(Opcodes.ASM5);
        this.classLoader = classLoader;
        this.source = source;
        this.annotationTypes = annotationType;
        this.consumer = consumer;
    }

    /**
     * TODO
     * 业务意义，ASM字节码解析
     * @param classLoader 类加载器
     * @param source 工厂全路径类名 E.g gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration
     * @param descriptor ASM字节码描述符,注解配置类 E.g： Lgang/org/springframework/framework/annotation/GConfiguration
     * @param visible 值 true
     * @param consumer 函数接口
     * */
    public static <A extends Annotation> AnnotationVisitor get(ClassLoader classLoader,
                                                               Object source,
                                                               String descriptor,
                                                               boolean visible,
                                                               Consumer<GangMergedAnnotation<A>> consumer){

        /**
         * TODO
         * 场景一
         * */

        /**
         * TODO
         * 场景二
         * */

        /**
         * TODO
         * 场景三
         * */
        String typeName = Type.getType(descriptor).getClassName();

        //类加载器，通过全类名获取，获取Class类对象，注解类类对象
        Class<A> annotationType = (Class<A>) GangClassUtils.forName(typeName, classLoader);

        GangMergedAnnotationReadingVisitor<A> gangMergedAnnotationReadingVisitor = new
                GangMergedAnnotationReadingVisitor<>(classLoader, source, annotationType, consumer);


        return gangMergedAnnotationReadingVisitor;
    }


    @Override
    public void visit(String name, Object value) {
        // TODO
        super.visit(name, value);
    }

    @Override
    public AnnotationVisitor visitAnnotation(String name, String desc) {
        return super.visitAnnotation(name, desc);
    }

    @Override
    public AnnotationVisitor visitArray(String name) {
        //TODO
        return new GangArrayVisitor(value -> this.attributes.put(name, value));
    }

    @Override
    public void visitEnum(String name, String desc, String value) {
        super.visitEnum(name, desc, value);
    }

    /**
     * TODO
     * 业务意义
     * 1）ASM字节码主类，解析注解
     * 2）实例化注解
     * 3）注解实例增加到集合中
     * param classLoader 类加载器
     * param source SimpleAnnotationMetadataReadingVisitor 内部类 E.g gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration
     * param Class<A> 类类对象 gang.org.springframework.framework.annotation.GConfiguration
     * param consumer 接口函数 List
     * */
    @Override
    public void visitEnd() {
        GangMergedAnnotation<A> annotation = GangMergedAnnotation.of(this.classLoader, this.source, this.annotationTypes,this.attributes);
        consumer.accept(annotation);
    }

    //TODO
    public class GangArrayVisitor extends AnnotationVisitor
    {
        private final List<Object> elements = new ArrayList<>();

        private final Consumer<Object[]>  consumer;

        GangArrayVisitor(Consumer<Object[]> consumer)
        {
            super(Opcodes.ASM5);
            this.consumer = consumer;
        }

        @Override
        public void visit(String name, Object value) {
            if (value instanceof jdk.internal.org.objectweb.asm.Type) {
                value = ((jdk.internal.org.objectweb.asm.Type) value).getClassName();
            }
            this.elements.add(value);
        }

        @Override
        public void visitEnum(String name, String descriptor, String value) {
            //TODO
        }

        @Override
        public AnnotationVisitor visitAnnotation(String name, String descriptor) {
            return super.visitAnnotation(name, descriptor);
        }


        @Override
        public void visitEnd() {
            Class<?> componentType = getComponentType();
            Object[] array = (Object[]) Array.newInstance(componentType, this.elements.size());
            this.consumer.accept(this.elements.toArray(array));
        }

        private Class<?> getComponentType()
        {
            if (this.elements.isEmpty()) {
                return Object.class;
            }

            Object firstElement = this.elements.get(0);
            //TODO

            return firstElement.getClass();
        }
    }
}
